home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DJGPP / DJSRC111.ZIP / go32 / ustat.c < prev    next >
C/C++ Source or Header  |  1993-06-20  |  5KB  |  183 lines

  1. #include <string.h>
  2. #include <errno.h>
  3. #include <dir.h>
  4. #include <sys/stat.h>
  5. #include <ctype.h>
  6.  
  7. #include "ustat.h"
  8.  
  9. /*
  10.  * An improved version of stat(). This version ensures that "." and ".."
  11.  * appear to exist in all directories, including Novell network drives, and
  12.  * that the root directory also returns the correct result.
  13.  *
  14.  * This function replaces any \'s with /'s in the input string, it should
  15.  * really take a copy of the string first, but this isn't necessary for go32
  16.  * which uses a transfer buffer between the program and the DOS extender
  17.  * anyway.
  18.  *
  19.  * Chris Boucher ccb@southampton.ac.uk
  20.  */
  21.  
  22.  
  23. /*
  24.  * I found the following function on SIMTEL20, it dates back to 1987 but
  25.  * there's no mention of who the author was. I've modified/fixed it quite
  26.  * a bit. It neatly avoids any problems with "." and ".." on Novell networks.
  27.  */
  28. static int rootpath(const char *relpath, char *fullpath);
  29.  
  30.  
  31. int unixlike_stat(char *name, struct stat *buf) {
  32.     static char path[2 * MAXPATH];
  33.     char *s = name;
  34.     int len;
  35.  
  36.     /* First off, try the standard stat(), if that works then all is well. */
  37.     if (stat(name, buf) == 0) {
  38.         return 0;
  39.     }
  40.  
  41.     /* Swap all \'s for /'s. */
  42.     while (*s) {
  43.         if (*s == '\\') *s = '/';
  44.         s++;
  45.     }
  46.  
  47.     /* Convert path name into root based cannonical form. */
  48.     if (rootpath(name, path) != 0) {
  49.         errno = ENOENT;
  50.         return -1;
  51.     }
  52.  
  53.     /* DOS doesn't stat "/" correctly, so fake it here. */
  54.     if (strcmp(path + 1, ":/") == 0
  55.         || strcmp(path+1, ":") == 0) {
  56.         buf->st_dev = 0;
  57.         buf->st_ino = 0;
  58.         buf->st_mode = S_IREAD | S_IWRITE | S_IFDIR;
  59.         buf->st_uid = buf->st_gid = 0;
  60.         buf->st_nlink = 1;
  61.         buf->st_rdev = 0;
  62.         buf->st_size = 0;
  63.         buf->st_atime = buf->st_mtime = buf->st_ctime = 0;
  64.         return 0;
  65.     }
  66.  
  67.     /* Now modify the string so that "dir/" works. */
  68.     len = strlen(path);
  69.     if (path[len - 1] == '/') path[len - 1] = '\0';
  70.     return stat(path, buf);
  71. }
  72.  
  73.  
  74. /*
  75.  * rootpath  --  convert a pathname argument to root based cannonical form.
  76.  *
  77.  * rootpath determines the current directory, appends the path argument (which
  78.  * may affect which disk the current directory is relative to), and qualifies
  79.  * "." and ".." references.  The result is a complete, simple, path name with
  80.  * drive specifier.
  81.  *
  82.  * If the relative path the user specifies does not include a drive spec., the
  83.  * default drive will be used as the base.  (The default drive will never be
  84.  * changed.)
  85.  *
  86.  *  entry: relpath  -- pointer to the pathname to be expanded
  87.  *         fullpath -- must point to a working buffer, see warning
  88.  *   exit: fullpath -- the full path which results
  89.  * return: -1 if an error occurs, 0 otherwise
  90.  *
  91.  * warning: fullpath must point to a working buffer large enough to hold the
  92.  *          longest possible relative path argument plus the longest possible
  93.  *          current directory path.
  94.  */
  95. static int rootpath(const char *relpath, char *fullpath) {
  96.     register char *lead, *follow, *s;
  97.     char tempchar;
  98.     int drivenum;
  99.  
  100.     /* Extract drive spec. */
  101.     if ((*relpath != '\0') && (relpath[1] == ':')) {
  102.         drivenum = toupper(*relpath) - 'A';
  103.         relpath += 2;
  104.     }
  105.     else {
  106.         drivenum = getdisk();
  107.     }
  108.  
  109.     /* Fill in the drive path. */
  110.     strcpy(fullpath, " :/");
  111.     fullpath[0] = drivenum + 'A';
  112.  
  113.     /* Get cwd for drive - also checks that drive exists. */
  114.     if (getcurdir(drivenum + 1, fullpath + 3) == -1) {
  115.         return -1;        /* No such drive - give up. */
  116.     }
  117.  
  118.     /* Swap all \'s for /'s. */
  119.     s = fullpath;
  120.     while (*s) {
  121.         if (*s == '\\') *s = '/';
  122.         s++;
  123.     }
  124.  
  125.     /* Append relpath to fullpath/base. */
  126.     if (*relpath == '/') {                /* relpath starts at base... */
  127.         strcpy(fullpath + 2, relpath);    /* ...so ignore cwd. */
  128.     }
  129.     else {                                /* relpath is relative to cwd. */
  130.         if (*relpath != '\0') {
  131.             if (strlen(fullpath) > 3) {
  132.                 strcat(fullpath, "/");    /* Add a '/' to end of cwd. */
  133.             }
  134.             strcat(fullpath, relpath);    /* Add relpath to end of cwd. */
  135.         }
  136.     }
  137.  
  138.     /* Convert path to cannonical form. */
  139.     lead = fullpath;
  140.     while (*lead != '\0') {
  141.         /* Mark next path segment. */
  142.         follow = lead;
  143.         lead = (char *)strchr(follow + 1, '/');
  144.         if (lead == 0) {
  145.             lead = fullpath + strlen(fullpath);
  146.         }
  147.         tempchar = *lead;
  148.         *lead = '\0';
  149.  
  150.         /* "." segment? */
  151.         if (strcmp(follow + 1, ".") == 0) {
  152.             *lead = tempchar;
  153.             strcpy(follow, lead);        /* Remove "." segment. */
  154.             lead = follow;
  155.         }
  156.  
  157.         /* ".." segment? */
  158.         else if (strcmp(follow + 1, "..") == 0) {
  159.             *lead = tempchar;
  160.             do {
  161.                 if (--follow < fullpath) {
  162.                     follow = fullpath + 2;
  163.                     break;
  164.                 }
  165.             } while (*follow != '/');
  166.             strcpy(follow, lead);        /* Remove ".." segment. */
  167.             lead = follow;
  168.         }
  169.  
  170.         /* Normal segment. */
  171.         else {
  172.             *lead = tempchar;
  173.         }
  174.     }
  175.  
  176.     if (strlen(fullpath) == 2) {        /* 'D:' or some such. */
  177.         strcat(fullpath, "/");
  178.     }
  179.  
  180.     /* All done. */
  181.     return 0;
  182. }
  183.